package ar.uba.fi.tecnicas.fabrica;

import java.util.Observable;

import ar.uba.fi.tecnicas.fabrica.exceptions.*;

public abstract class ItemLineaProduccion extends Observable
{
	protected Pieza pieza = null;	

	protected ItemLineaProduccion entrada = null;
	protected ItemLineaProduccion salida = null;
	
	protected LineaProduccion lineaProduccion = null;

	protected PosicionTerreno posicion;
	
	// Indica si la maquina puede recibir una pieza
	public final boolean inactivo()
	{		
		return this.pieza == null;
	}

	public Pieza entregar()
	{
		Pieza piezaTemp = this.pieza;

		piezaTemp.entregar();

		this.pieza = null;
		
		this.notifyObservers();

		return piezaTemp;
	}
	
	public final boolean recibir(Pieza pieza)
	{
		boolean ingresar = false;
		try
		{
			this.validarIngresar(pieza);
			pieza.validarIngresar(this);
			
			this.pieza = pieza;
			pieza.ingresar(this);
			
			this.procesar();
			
			ingresar = true;
			
			this.notifyObservers();
		}
		catch(PiezaInvalidaException ex) {}
		catch(PiezaConItemAsignadoException ex) {}
		catch(NullPointerException ex) {}
		
		return ingresar;
	}
	
	/// Realiza la validacion de la pieza que ingresa 
	protected abstract void validarIngresar(Pieza pieza) throws PiezaInvalidaException;
	
	/// Metodo en el que se implementa lo que cada item hace con la pieza
	protected abstract void procesar();

	/// Valida el agregado de este item a una linea de produccion
	public void validarAgregarItem(LineaProduccion lineaProduccion) throws ItemConLineaProduccionAsignadaException
	{
		if(this.lineaProduccion != null)
			throw new ItemConLineaProduccionAsignadaException();
	}
	
	/// Asocia el item a una linea de produccion
	public void agregarLineaProduccion(LineaProduccion lineaProduccion) 
	{
		this.lineaProduccion = lineaProduccion;
	}

	/// Devuelve el item conectado a la entrada de este o null si no hay ninguno
	public ItemLineaProduccion getEntrada() 
	{
		return this.entrada;
	}

	/// Devuelve el item conectado a la salida de este o null si no hay ninguno
	public ItemLineaProduccion getSalida() 
	{
		return this.salida;
	}
	
	public boolean verificarPadre(Object padre)
	{
		return this.lineaProduccion.equals(padre);
	}

	public LineaProduccion getLineaProduccion()
	{
		return this.lineaProduccion;
	}
	
	public PosicionTerreno getPosicion() 
	{
		return this.posicion;
	}
	
	public abstract ItemLineaProduccionInfo getInfo();
	
	public class ItemLineaProduccionInfo
	{
		public String nombre;
		public String descripcion;
		
		public ItemLineaProduccionInfo(String nombre, String descripcion)
		{
			this.nombre = nombre;
			this.descripcion = descripcion;
		}

		public String getNombre()
		{
			return this.nombre;
		}
		
		public String getDescripcion()
		{
			return this.descripcion;
		}
	}
	
	public EspecificacionItemLineaProduccion getEspecificacion()
	{
		return new EspecificacionItemLineaProduccion(this);
	}
}
